package com.kurt.service.impl;

import com.kurt.dto.query.SysOperLogQueryRequest;
import com.kurt.entity.SysOperLog;
import com.kurt.repository.SysOperLogRepository;
import com.kurt.service.SysOperLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 操作日志服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysOperLogServiceImpl extends BaseServiceImpl<SysOperLog, String> implements SysOperLogService {

    private final SysOperLogRepository operLogRepository;

    @Override
    protected SysOperLogRepository getRepository() {
        return operLogRepository;
    }

    @Override
    protected SysOperLogRepository getSpecificationExecutor() {
        return operLogRepository;
    }

    @Override
    @Async
    public void asyncInsertOperLog(SysOperLog operLog) {
        try {
            insertOperLog(operLog);
        } catch (Exception e) {
            log.error("异步插入操作日志失败", e);
        }
    }

    @Override
    @Transactional
    public SysOperLog insertOperLog(SysOperLog operLog) {
        try {
            // 生成唯一ID
            if (!StringUtils.hasText(operLog.getId())) {
                operLog.setId(UUID.randomUUID().toString());
            }

            // 设置操作时间
            if (operLog.getOperTime() == null) {
                operLog.setOperTime(LocalDateTime.now());
            }

            // 设置默认值
            if (operLog.getStatus() == null) {
                operLog.setStatus(0); // 默认正常
            }
            if (operLog.getBusinessType() == null) {
                operLog.setBusinessType(0); // 默认其它
            }
            if (operLog.getOperatorType() == null) {
                operLog.setOperatorType(0); // 默认其它
            }
            if (operLog.getCostTime() == null) {
                operLog.setCostTime(0L);
            }

            return operLogRepository.save(operLog);
        } catch (Exception e) {
            log.error("插入操作日志失败", e);
            throw e;
        }
    }

    @Override
    public List<SysOperLog> getLogsByOperName(String operName) {
        return operLogRepository.findByOperName(operName);
    }

    @Override
    public List<SysOperLog> getLogsByBusinessType(Integer businessType) {
        return operLogRepository.findByBusinessType(businessType);
    }

    @Override
    public List<SysOperLog> getLogsByStatus(Integer status) {
        return operLogRepository.findByStatus(status);
    }

    @Override
    public List<SysOperLog> getLogsByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
        return operLogRepository.findByOperTimeBetween(startTime, endTime);
    }

    @Override
    public List<SysOperLog> getLogsByOperNameAndTimeRange(String operName, LocalDateTime startTime, LocalDateTime endTime) {
        return operLogRepository.findByOperNameAndOperTimeBetween(operName, startTime, endTime);
    }

    @Override
    @Transactional
    public int cleanLogsBefore(LocalDateTime operTime) {
        try {
            List<SysOperLog> logsToDelete = operLogRepository.findByOperTimeBefore(operTime);
            int count = logsToDelete.size();
            operLogRepository.deleteByOperTimeBefore(operTime);
            log.info("清理了{}条操作日志", count);
            return count;
        } catch (Exception e) {
            log.error("清理操作日志失败", e);
            throw e;
        }
    }

    @Override
    public Page<SysOperLog> getLogsPage(SysOperLogQueryRequest request) {
        // 构建分页参数
        Pageable pageable = PageRequest.of(request.getPageNum() - 1, request.getPageSize(), Sort.by(Sort.Direction.DESC, "operTime"));

        // 构建查询条件
        Specification<SysOperLog> spec = buildOperLogSpecification(request.getOperName(), request.getBusinessType(),
                request.getStatus(), request.getCreateTimeStart(), request.getCreateTimeEnd());

        // 执行分页查询
        return operLogRepository.findAll(spec, pageable);
    }

    /**
     * 构建操作日志查询条件
     */
    private Specification<SysOperLog> buildOperLogSpecification(String operName, Integer businessType,
                                                                Integer status, String startTime, String endTime) {
        return (root, query, cb) -> {
            List<jakarta.persistence.criteria.Predicate> predicates = new ArrayList<>();

            // 操作人员查询
            if (StringUtils.hasText(operName)) {
                predicates.add(cb.like(root.get("operName"), "%" + operName + "%"));
            }

            // 业务类型查询
            if (businessType != null) {
                predicates.add(cb.equal(root.get("businessType"), businessType));
            }

            // 操作状态查询
            if (status != null) {
                predicates.add(cb.equal(root.get("status"), status));
            }

            // 操作时间范围查询
            if (startTime != null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("operTime"), startTime));
            }
            if (endTime != null) {
                predicates.add(cb.lessThanOrEqualTo(root.get("operTime"), endTime));
            }

            return cb.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
        };
    }
}
